package com.distribute.core.netty.handler;

import com.distribute.core.init.CacheReportClient;
import com.distribute.core.netty.retry.RetryPolicy;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * 断线重连
 *
 * @author chennengcheng
 * @date 2021-09-22 15:49
 * @remark
 */

@ChannelHandler.Sharable
public class ReconnectHandler extends ChannelInboundHandlerAdapter {
    private static final Logger log = LoggerFactory.getLogger(ReconnectHandler.class);

    private int retries = 0;
    private RetryPolicy retryPolicy;

    private CacheReportClient tcpClient;

    public ReconnectHandler(CacheReportClient tcpClient) {
        this.tcpClient = tcpClient;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("Successfully established a connection to the server.");
        retries = 0;
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (retries == 0) {
            ctx.channel().pipeline().remove(CacheMemoryInfoHandler.class);
            ctx.channel().pipeline().remove(MemoryStaticsHandler.class);
            ctx.close();
        }

        boolean allowRetry = getRetryPolicy().allowRetry(retries);
        if (allowRetry) {
            long sleepTimeMs = getRetryPolicy().getSleepTimeMs(retries);
            if (retries != 0) {
                log.info("Try to reconnect to the server after {}ms. Retry count: {}", sleepTimeMs, retries);
            }

            final EventLoop eventLoop = ctx.channel().eventLoop();
            eventLoop.schedule(() -> {
                if (retries != 0) {
                    log.info("Reconnecting ...");
                }

                tcpClient.connect();
            }, sleepTimeMs, TimeUnit.MILLISECONDS);
        }

        ++retries;
        ctx.fireChannelInactive();
    }


    private RetryPolicy getRetryPolicy() {
        if (this.retryPolicy == null) {
            this.retryPolicy = tcpClient.getRetryPolicy();
        }
        return this.retryPolicy;
    }
}